package com.zwb.demo.reader;

import com.alibaba.fastjson.JSONObject;
import com.zwb.demo.exception.ConfigException;
import com.zwb.demo.exception.ExceptionEnum;
import com.zwb.demo.model.FieldDefinition;
import com.zwb.demo.model.SheetDefinition;
import com.zwb.demo.utils.MyExcelUtils;
import com.zwb.demo.utils.MyFreeMarkerUtils;
import com.zwb.demo.utils.MyStringUtils;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.commons.text.translate.AggregateTranslator;
import org.apache.commons.text.translate.EntityArrays;
import org.apache.commons.text.translate.LookupTranslator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.*;

@Slf4j
@Component
public class Main {

    @Value("${excel-input-dir}")
    private String excelDir;
    @Value("${json-output-dir}")
    private String jsonOutPutDir;
    @Value("${java-output-dir}")
    private String javaOutPutDir;
    @Value("${lua-output-dir}")
    private String luaOutPutDir;
    @Value("${go-output-dir}")
    private String goOutPutDir;
    @Value("${java-package}")
    private String javaPackage;

    private final ExcelParser excelParser;

    @Autowired
    public Main(ExcelParser excelParser) {
        this.excelParser = excelParser;
    }

    public void main() throws Exception {
        File excelDirFile = new File(excelDir);
        log.info("excel配置目录:{}", excelDirFile.getAbsolutePath());
        if (!excelDirFile.exists()) {
            throw new ConfigException(ExceptionEnum.EXCEL_DIR_NO_EXITS);
        }
        if (!excelDirFile.isDirectory()) {
            throw new ConfigException(ExceptionEnum.EXCEL_DIR_NO_DIR);
        }
        File[] files = excelDirFile.listFiles();
        List<File> excelFileList = new ArrayList<>();
        assert files != null;
        for (File file : files) {
            if (!MyExcelUtils.isExcel(file)) {
                log.info("过滤掉非excel文件：{}", file.getName());
                continue;
            }
            excelFileList.add(file);
        }
        checkOutputPath();
        Map<String, SheetDefinition> sheetDefinitionMap = new HashMap<>();
        //解析文件
        for (File file : excelFileList) {
            try {
                List<SheetDefinition> sheetDefinitions = excelParser.parse(file);
                for (SheetDefinition sheetDefinition : sheetDefinitions) {
                    sheetDefinitionMap.put(sheetDefinition.getSheetName(), sheetDefinition);
                }

            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        //生成文件
        genJsonFile(sheetDefinitionMap);
        genJavaFile(sheetDefinitionMap);
        genLuaFile(sheetDefinitionMap);
        genGoFile(sheetDefinitionMap);
        log.info("生成完毕!");
    }

    private void genGoFile(Map<String, SheetDefinition> sheetDefinitionMap) throws IOException, TemplateException {
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("package", javaPackage);
        dataMap.put("containers", sheetDefinitionMap.values().stream().map(s -> s.getSheetName() + "Container").toArray());
        MyFreeMarkerUtils.createFile("golang/GameDataManager.ftl", goOutPutDir, "GameDataManager.go", dataMap);
        for (SheetDefinition sheetDefinition : sheetDefinitionMap.values()) {
            MyFreeMarkerUtils.createFile("golang/Bean.ftl", goOutPutDir + "/bean", sheetDefinition.getSheetName() + "Bean.go", sheetDefinition);
            MyFreeMarkerUtils.createFile("golang/Container.ftl", goOutPutDir + "/", sheetDefinition.getSheetName() + "Container.go", sheetDefinition);
        }

    }


    private void genLuaFile(Map<String, SheetDefinition> sheetDefinitionMap) throws IOException {
        for (SheetDefinition sheetDefinition : sheetDefinitionMap.values()) {
            Map<CharSequence, CharSequence> escapeJavaMap = new HashMap<>();
            escapeJavaMap.put("\"", "\\\"");
//            escapeJavaMap.put("\\", "\\\\");
            escapeJavaMap.put("\b", "\\b");
//            escapeJavaMap.put("\n", "\\n");
            escapeJavaMap.put("\t", "\\t");
            escapeJavaMap.put("\f", "\\f");
            escapeJavaMap.put("\r", "\\r");
            AggregateTranslator aggregateTranslator = new AggregateTranslator(
                    new LookupTranslator(Collections.unmodifiableMap(escapeJavaMap)));
            StringEscapeUtils.Builder builder = StringEscapeUtils.builder(aggregateTranslator);
            builder.append(sheetDefinition.getSheetName()).append("={");
            for (int i = 0; i < sheetDefinition.getJsonArray().size(); i++) {
                JSONObject jsonObject = sheetDefinition.getJsonArray().getJSONObject(i);
                Integer keyValue = jsonObject.getInteger(sheetDefinition.getKeyName());
                builder.append("[").append(String.valueOf(keyValue)).append("]={");
                for (FieldDefinition field : sheetDefinition.getFields()) {
                    String k = field.getFieldName();
                    Object v ;
                    if (field.getJavaClass().equals("int")){
                        v = jsonObject.getIntValue(k);
                    }else {
                        v = jsonObject.get(k);
                    }
                    if (v == null){
                        log.error("值为null==={}, {},{}",sheetDefinition.getSheetName(),field.getFieldName(),jsonObject );
                        continue;
                    }
                    builder.append(MyStringUtils.unCapFirst(k)).append("=");
                    if (v.getClass().equals(String.class)){
                        builder.append("\"").escape((String) v).append("\"");
                    }else if (v.getClass().equals(int[].class)){
                        builder.append("\"").append(Arrays.toString((int[]) v)).append("\"");
                    } else if ( v.getClass().equals(int[][].class)){
                        builder.append("\"").append(Arrays.deepToString((int[][]) v)).append("\"");
                    } else {
                        builder.append(String.valueOf(v));
                    }
                    builder.append(",");
                }
                jsonObject.getInnerMap().forEach((k,v)->{

                });
                builder.append("},\n");
            }

            builder.append("}");
            String jsonFilePath = luaOutPutDir + sheetDefinition.getSheetName() + ".lua.txt";
            File file = new File(jsonFilePath);
            FileUtils.write(file, builder.toString(), "utf-8");
        }
    }

    /**
     * 生成java文件
     */
    private void genJavaFile(Map<String, SheetDefinition> sheetDefinitionMap) throws IOException, TemplateException {
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("package", javaPackage);
        dataMap.put("containers", sheetDefinitionMap.values().stream().map(s -> s.getSheetName() + "Container").toArray());
        MyFreeMarkerUtils.createFile("java/GameDataManager.ftl", javaOutPutDir, "GameDataManager.java", dataMap);
        for (SheetDefinition sheetDefinition : sheetDefinitionMap.values()) {
            MyFreeMarkerUtils.createFile("java/Bean.ftl", javaOutPutDir + "/bean", sheetDefinition.getSheetName() + "Bean.java", sheetDefinition);
            MyFreeMarkerUtils.createFile("java/Container.ftl", javaOutPutDir + "/container", sheetDefinition.getSheetName() + "Container.java", sheetDefinition);
        }
    }

    /**
     * 检查输出目录
     */
    private void checkOutputPath() {
        File jsonOutPutDirFile = new File(jsonOutPutDir);
        if (!jsonOutPutDirFile.exists()) {
            jsonOutPutDirFile.mkdirs();
        }
        log.info("json文件输出目录:{}", jsonOutPutDirFile.getAbsolutePath());
        File javaOutPutDirFile = new File(javaOutPutDir);
        if (!javaOutPutDirFile.exists()) {
            javaOutPutDirFile.mkdirs();
        }
        log.info("java文件输出目录:{}", javaOutPutDirFile.getAbsolutePath());
        File luaOutPutDirFile = new File(luaOutPutDir);
        if (!luaOutPutDirFile.exists()) {
            luaOutPutDirFile.mkdirs();
        }
        log.info("lua文件输出目录:{}", luaOutPutDirFile.getAbsolutePath());
    }

    /**
     * 生成json文件
     */
    private void genJsonFile(Map<String, SheetDefinition> sheetDefinitionMap) throws IOException {
        for (SheetDefinition sheetDefinition : sheetDefinitionMap.values()) {
            String jsonFilePath = jsonOutPutDir + sheetDefinition.getSheetName() + "Bean.json";
            File file = new File(jsonFilePath);
            FileUtils.write(file, sheetDefinition.getJsonData(), "utf-8");
        }

    }
}
